#pragma once

#ifndef UTIL_H
#define UTIL_H

#include <iostream>
#include <ctime>

#include "boost/format.hpp"
#include "boost/algorithm/string.hpp"

namespace analyzer {
	
	extern std::ostream* gpOut;
	
	
	template <typename T,typename Operation>
	void for_all(T& t,Operation Op) {
		std::for_each(t.begin(),t.end(),Op);
	}

	enum Level {	
		DEBUG,
		INFO,
		ERROR
	};

	extern Level logLevel;

	inline Level getLogLevel(void) {
		return logLevel;
	}

	inline void setLogLevel(Level level) {
		logLevel = level;
	}

	inline std::string getCurrentTime() {
		time_t rawtime;
		tm * timeinfo;

		time( &rawtime );
		timeinfo = localtime(&rawtime);

		std::string result(asctime(timeinfo));

		boost::trim(result);

		return result;
	}

	inline std::string logLevelToString(Level level) {
		switch(level) {
		case DEBUG:
			return std::string("DEBUG");
			break;
		case INFO:
			return std::string("INFO");
			break;
		default:
			return std::string("ERROR");		
		}
	}


	inline void log(Level level, std::string message) {

		if(level >= getLogLevel()) {
			*gpOut << "[" << getCurrentTime() << "] [" << logLevelToString(level) << "] " << message << std::endl;
		}
	}
	
	inline void log(Level level, boost::format fmter) {

		log(level, fmter.str());
	}
	
	inline void log(Level level, std::string className, std::string methodName, std::string message) {

		if(level >= getLogLevel()) {
			*gpOut << "[" << getCurrentTime() << "] [" << logLevelToString(level) << "] [" << className << "::" << methodName << "] " << message << std::endl;
		}
	}

	inline void log(Level level, std::string className, std::string methodName, boost::format fmter) {

		log(level, className, methodName, fmter.str());
	}

}

#endif // UTIL_H
